package dk.aau.cs.giraf.TimerLib;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.View;
/**
 * 
 * This class represent either; educator, parent, or similar.
 * This class uses the singleton pattern, to enforce there only exists one object, and you always work with this one object.
 * This class contains all "super" methods e.g. remove and save.
 * Layer: CRUD
 *
 */
public class Guardian{

	//Version number: x.y
	//Example version: 1.2
	//x = Major version number, change this whenever TimerLib has evolved to a state where it seems new.
	//y = Minor version number, change this whenever TimerLib is released and used in WOMBAT public.
	public double TIMERLIB_VERSION = 1.0;

	//Version number: x.y
	//Example version: 1.2
	//x = Major version number, change this whenever WOMBAT has evolved to a state where it seems new.
	//y = Minor version number, change this whenever WOMBAT is released and used public.
	public double WOMBAT_VERSION;

	//Guardian singleton instance
	private static Guardian _instance = null;


	//View of the selected ChildView
	public View ChildView = null;

	//View of the selected SubProfileView
	public View SubProfileView = null;

	private CRUD CRUD = null;


	private ArrayList<Child> _guard = null;

	private ArrayList<SubProfile> _lastUsed = null;

	private ArrayList<SubProfile> _predef = null;

	private ArrayList<Child> _sortedList = null;

	//Selected Child
	private Child _selectedChild = null;
	//Selected SubProfile
	private SubProfile _selectedSubProfile = null;
	//List of all Art objects
	public ArrayList<Art> ArtList = new ArrayList<Art>();

	public String _name = null;

	private int id = -1;

	private int _artId = -1;

	Context context;

	// Stores the id of the saved subprofile
	public long subProfileID;
	// When a subprofile is saved, this is set to true
	public boolean subProfileFirstClick;
	// When something is clicked in the subprofile list, set to false
	public boolean profileFirstClick;
	public int backgroundColor;

	private ArrayList<formFactor> _mode = null;
	/**
	 * Generate id for the art class
	 * @return int id
	 */
	int getArtId(){
		this._artId++;
		return this._artId;
	}

	/**
	 * Used to reset the guardian class, if the guardian object need to represent another educator, parent, etc.
	 */
	public void reset(){
		_instance = null;
	}
	/**
	 * ArrayList with three formFactors, Timer, SingleImg, SplitImg.
	 * This is used for the ModeAdapter in WOMBAT
	 * @return
	 */
	public ArrayList<formFactor> getMode(){
		if(_mode == null){
			_mode = new ArrayList<formFactor>();
			_mode.add(formFactor.Timer);
			_mode.add(formFactor.SingleImg);
			_mode.add(formFactor.SplitImg);
			return _mode;
		}  else {
			return _mode;
		}
	}

	/**
	 * Default constructor for Guardian, may only be used within the guardian class.
	 */
	private Guardian(){	
	}

	/**
	 * Generate a new id
	 * @return id
	 */
	int getId(){
		id++;
		return id;
	}

	void setId(int id){
		this.id = id;
	}

	/**
	 * Singleton constructor for guardian.
	 * Always use this instead of the default constructor.
	 * 
	 * Example:
	 * Guardian guard = Guadian.getInstance();
	 * @return Guardian instance
	 * @throws FileNotFoundException 
	 */
	public static Guardian getInstance(Context c, ArrayList<Art> artList, double wombat_version){
		if(_instance == null){
			//Create Guardian instance
			_instance = new Guardian();
			//Set the according WOMBAT version
			_instance.WOMBAT_VERSION = wombat_version;
			//Load the list of art
			_instance.ArtList = artList;
			//Set the proper context
			_instance.context = c;
			//Load the predefined profiles from the TimerHelper class
			new TimerHelper().loadPredef();
			//Create a common list for all the Child objects
			_instance.publishList();	
			//CRUD instance
			_instance.CRUD = new CRUD();
			//Load saved settings
			_instance.CRUD.init();
		}
		return _instance;
	}

	/**
	 * Used to retrieve the guardian object
	 * @return Guardian object
	 */
	public static Guardian getInstance(){
		return _instance;
	}

	/***
	 * List of default colors
	 * @return A list of all the defined colors in WOMBAT.
	 */
	public ArrayList<Integer> colorList(){
		ArrayList<Integer> colorArray = new ArrayList<Integer>();
		Color color = new Color();

		//Colors from android
		colorArray.add(color.BLACK); colorArray.add(color.BLUE); colorArray.add(color.CYAN);
		colorArray.add(color.DKGRAY); colorArray.add(color.GRAY); colorArray.add(color.GREEN);
		colorArray.add(color.LTGRAY); colorArray.add(color.MAGENTA); colorArray.add(color.RED);
		colorArray.add(color.WHITE); colorArray.add(color.YELLOW);

		//Colors from launcher
		colorArray.add(0xFF78D1A7); colorArray.add(0xFFB993F4);	colorArray.add(0xFF4A62F2);
		colorArray.add(0xFFC1804F); colorArray.add(0xFF56DBFC);	colorArray.add(0xFFE4C08F);
		colorArray.add(0xFF5881F4); colorArray.add(0xFF5F6FA3); colorArray.add(0xFF74B21E);
		colorArray.add(0xFFB77888);

		return colorArray;
	}

	/**
	 * Stores the subprofile on the child in Oasis
	 * @param c
	 * 		The Child where the subprofile is supposed to be stored
	 * @param sp
	 * 		The subprofiel which is to be stored
	 * @return
	 * 		Returns true if it completed, else returns false
	 */
	public void saveChild(Child c, SubProfile sp){
	}

	/**
	 * ArrayList Children of Child object type
	 * @return ArrayList<Child>
	 */
	public ArrayList<Child> Children(){
		if(_guard == null){
			_guard = new ArrayList<Child>();
		}
		return _guard;
	}

	/**
	 * ArrayList lastUsed of SubProfile object type
	 * @return ArrayList<SubProfile> lastUsed
	 */
	private ArrayList<SubProfile> lastUsed(){
		if(_lastUsed == null){
			_lastUsed = new ArrayList<SubProfile>();
		}
		return _lastUsed;
	}

	/**
	 * getChild is used to return a selected child
	 * @return selected child
	 */
	public Child getChild(){
		return _selectedChild;
	}

	/**
	 * Selects a specific child
	 * @param c The child you wish to select
	 */
	void setChild(Child c){
		_selectedChild = c;
	}

	/**
	 * getSubProfile is used to return a selected SubProfile
	 * @return selected subprofile
	 */
	public SubProfile getSubProfile(){
		return _selectedSubProfile;
	}
	/**
	 * Select a specific SubProfile
	 * @param p The SubProfile you wish to select
	 */
	void setSubProfile(SubProfile p){
		_selectedSubProfile = p;
	}

	//Waiting for admin
	void initLastUsed(ArrayList<SubProfile> profile){
		_lastUsed = new ArrayList<SubProfile>();
		for(SubProfile p : profile){
			_lastUsed.add(p);
		}
	}

	private ArrayList reverse(ArrayList list){
		ArrayList value = new ArrayList();
		for(int i = list.size()-1; i > -1; i--){
			value.add(list.get(i));
		}
		return value;
	}

	/**
	 * Add a SubProfile to the list of lastUsed
	 * @param profile The SubProfile which you want to add to the lastUsed list
	 */
	public void addLastUsed(SubProfile NewProfile, SubProfile OldProfile){
		if(OldProfile != null){
			lastUsed().remove(OldProfile);
			lastUsed().add(NewProfile);
		} else {
			lastUsed().add(NewProfile);
		}
	}

	/**
	 * Clears last
	 */
	public void clearLastUsed(){
		if(_lastUsed != null){
			_lastUsed.clear();
		}
	}

	/**
	 * ArrayList of predefined of the SubProfile Object type
	 * @return ArrayList<SubProfile> predefined profiles
	 */
	ArrayList<SubProfile> predefined(){
		if(_predef == null){
			_predef = new ArrayList<SubProfile>();
		}
		return _predef;
	}
	/**
	 * This method is use to generate a list of lastUsed, predefined and all the children.
	 * ONLY use this method when you wish to generate a list of all the lists. Never use this list to execute methods on.
	 * @return A sorted list of lastUsed, predefined and all the children.
	 */
	public ArrayList<Child> publishList(){
		if(_sortedList == null){
			_sortedList = new ArrayList<Child>();
		}

		_sortedList.clear();
		Child lastUsedChild = new Child("Last Used");
		lastUsedChild.SubProfiles().addAll(reverse(lastUsed()));
		lastUsedChild.setLock();
		lastUsedChild.lockDelete();
		_sortedList.add(lastUsedChild);

		Child predefChild = new Child("Predefined Profiles");
		Collections.sort(predefined());
		predefChild.SubProfiles().addAll(predefined());
		predefChild.setLock();
		predefChild.lockDelete();
		_sortedList.add(predefChild);

		if(_guard != null){
			Collections.sort(_guard);
			for(Child p : _guard){
				Collections.sort(p.SubProfiles());
			}
			_sortedList.addAll(_guard);
		}

		return _sortedList;
	}

	/**
	 * Used to delete a certains SubProfile from the OasisLocalDatabase
	 * @param c The child who contains the SubProfile
	 * @param subProfile The SubProfile which you want to delete
	 */
	public void delete(Child c, SubProfile subProfile) {
		if(subProfile != null){
			//Delete specific SubProfile
			CRUD.delete(String.valueOf(subProfile.getId()));
			c.SubProfiles().remove(subProfile);
		} else {
			//Delete a Child object and all its SubProfiles
			for(SubProfile sp: c.SubProfiles()){
				CRUD.delete(String.valueOf(sp.getId()));
			}
			CRUD.delete(String.valueOf(c.getId()));
		}
		//TODO: DELETE THIS
		//Toast.makeText(m_context, subProfile.getDB_id() + " ", Toast.LENGTH_SHORT).show(););
	}

	public Child createChild(String name){
		Child c = new Child(name);
		this.Children().add(c);
		publishList();
		saveChild(c);
		return c;
	}

	void saveSubProfile(Child c, SubProfile sp){
		//Save the SubProfile
		CRUD.write(String.valueOf(sp.getId()), sp.getHashMap());
		saveChild(c);
		//Save the child aswell, since it has been altered
	}

	void saveChild(Child c){
		//Save the child
		seriaChild seriaChild = new seriaChild(c.getChildSave().getId(),c.getChildSave().name,c.getChildSave()._subprofiles);
		CRUD.write(String.valueOf(c.getId()), seriaChild);
		//Generate new meta file
		CRUD.genMETA();
	}

}